const TRACK_SIGN = { 0: '▁', 1: '▄', 2: '█' };
const ROBOT_SIGN = { 0: '□', 1: '■' };
const WIDTH_SIGN = { 0: '０', 1: '１', 2: '２' }; 

/* translate rule*/
const TR = {
  0: {
    0: { B: 0, T: 0 },
    1: { B: 1, T: 0 },
    2: { B: 0, T: 1 },
  },
  1: {
    0: { B: 1, T: 1 },
    1: { B: 0, T: 2 },
    2: { B: 1, T: 2 },
  }
};

/**
 * single machine {B,T,D,E}
 * useLess now
 * @param D direction {0:"Left",1:"Right"} 
 * @param E edge      
 */
const SM = ({ B = 0, T = 0, D = 0, E = 0 }) => {
  if (E) {
    if (D & B) {
      return { B: 0, T: 2 };
    }
    if (!D & T) {
      return { B: 1, T: T - 1 }
    }
  }
  return TR[B][T];
}

let Bs = [], Ts = [];

const BLoop = num => {
  // return Array.from(num.toString(2)).map(e => ({ B: +e, T: 0 }));
  // while (!(num & 1)) num = num >> 1;
  if (num <= 4) return;
  Bs.length = 0;
  Ts.length = 0;
  Bs = Array.from(num.toString(2)).map(e => +e);

  let f1 = typeof cb1 === "function";
  let f2 = typeof cb2 === "function";
  let bt;

  while (Ts.some(e => !!e) || Bs.length >= 3) {
    // clear the zeros after the array
    while (!(Ts[Ts.length -1] || Bs[Bs.length-1])) {
      Bs.pop();
      Ts.pop();
    }

    f1 ? cb1() : null;

    // first input
    Bs[Bs.length - 1] = 0;
    Ts.push(2);

    for (let length = Math.min(Bs.length, Ts.length), i = 1; i <= length; i++) {
      f2 ? cb2() : null;

      bt = TR[Bs[Bs.length - i]][Ts[Ts.length - i]];
      Bs[Bs.length - i] = bt.B;
      Ts[Ts.length - i] = bt.T;
    }

    // terminal move
    if (Bs.length < Ts.length) {
      if (!(Ts[Ts.length -1] || Bs[Bs.length-1])) {
        Ts.shift();
        Bs.shift();
      } else {
        Ts[Ts.length -1] = Ts[Ts.length -1] - 1;
        Bs.unshift(1);
      }
    }

  }

}

const TLoop = (num, cb1, cb2) => {
  // return Array.from(num.toString(3)).map(e => ({ T: +e, B: 0 }));
  if (num <= 4) return;

  Bs.length = 0;
  Ts.length = 0;
  Ts = Array.from(num.toString(2)).map(e => +e);

  let f1 = typeof cb1 === "function";
  let f2 = typeof cb2 === "function";
  let bt;

  while (Bs.some(e => !!e) || Ts.length >= 2) {
    f1 ? cb1() : null;

    // first input
    Bs.unshift(0);

    for (let length = Math.min(Bs.length, Ts.length), i = 0; i <= length - 1; i++) {
      f2 ? cb2() : null;

      bt = TR[Bs[i]][Ts[i]];
      Bs[i] = bt.B;
      Ts[i] = bt.T;
    }

    // terminal move
    if (Bs.length > Ts.length) {
      if (Bs[Bs.length - 1]) {
        Ts.push(2);
      }
      Bs.pop();
    }

    // clear the zeros ahead the array
    while (!(Ts[0] || Bs[0])) {
      Bs.shift();
      Ts.shift();
    }
  }
}
